package com.kinghood.productcenter.service.base.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.infrastructure.api.authority.UserRemoteVo;
import com.kinghood.infrastructure.model.KingHoodException;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.model.dto.StatusReqDTO;
import com.kinghood.infrastructure.model.enums.StatusEnum;
import com.kinghood.infrastructure.util.UserUtil;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.productcenter.common.api.authority.UserRemote;
import com.kinghood.productcenter.common.model.dao.base.*;
import com.kinghood.productcenter.common.model.dao.product.ProductBaseDO;
import com.kinghood.productcenter.common.model.dto.base.*;
import com.kinghood.productcenter.common.model.dto.product.ProductTemplateNodeAttributeDTO;
import com.kinghood.productcenter.common.model.dto.product.ProductTemplateNodeDTO;
import com.kinghood.productcenter.common.model.enums.base.AttributeValueCodeEnum;
import com.kinghood.productcenter.common.model.vo.base.TemplateListVO;
import com.kinghood.productcenter.common.model.vo.product.ProductTemplateInfoVO;
import com.kinghood.productcenter.common.utils.UserNameUtil;
import com.kinghood.productcenter.dao.base.BaseAttributeValueMapper;
import com.kinghood.productcenter.dao.base.BaseProductTemplateGitemMapper;
import com.kinghood.productcenter.dao.base.BaseProductTemplateMapper;
import com.kinghood.productcenter.dao.base.BaseProductTemplateRuleMapper;
import com.kinghood.productcenter.dao.product.ProductBaseMapper;
import com.kinghood.productcenter.service.base.IBaseProductTemplateService;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础选项-模板 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-20
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class BaseProductTemplateServiceImpl extends ServiceImpl<BaseProductTemplateMapper, BaseProductTemplateDO> implements IBaseProductTemplateService {

    private final BaseProductTemplateGitemMapper itemMapper;
    private final BaseProductTemplateRuleMapper ruleMapper;
    private final BaseProductTemplateGitemServiceImpl templateGitemService;
    private final BaseProductTemplateGroupServiceImpl templateGroupService;
    private final BaseProductTemplateRuleServiceImpl templateRuleService;
    private final BaseAttributeValueMapper attributeValueMapper;
    private final ProductBaseMapper productBaseMapper;
    private final UserRemote userRemote;

    @Override
    public ProductTemplateInfoVO getProductTemplateById(Long id, boolean style) {

        BaseProductTemplateDO productTemplateDO = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(BaseProductTemplateDO::getStatus, CommonConstants.ENABLE)
                .eq(BaseProductTemplateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(Objects.nonNull(id),BaseProductTemplateDO::getId, id)
                .eq(Objects.isNull(id),BaseProductTemplateDO::getIsDefault, CommonConstants.ENABLE)
                .last("limit 1")
                .one();
        ProductTemplateInfoVO res = new ProductTemplateInfoVO();
        List<BaseProductTemplateGroupDO> groupList = this.getBaseMapper().getGroupByTemplateId(productTemplateDO.getId());
        if (CollectionUtils.isEmpty(groupList)) {
            return null;
        }
        BeanUtils.copyProperties(productTemplateDO,res);
        res.setProductTemplateId(productTemplateDO.getId());

        // 得到父节点
        ArrayList<ProductTemplateNodeDTO> allGroupList = new ArrayList<>();
        List<ProductTemplateNodeDTO> headList = groupList.stream()
                .filter(x -> Objects.isNull(x.getParentId()))
                .map(x -> {
                    ProductTemplateNodeDTO node = new ProductTemplateNodeDTO();
                    node.setId(x.getId());
                    node.setGroupId(x.getId());
                    node.setGroupCode(x.getGroupCode());
                    node.setGroupName(x.getGroupName());
                    node.setIsMultiple(x.getIsMultiple());
                    node.setSort(x.getSort());
                    return node;
                })
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(headList)) {
            return res;
        }
        allGroupList.addAll(headList);
        res.setNodeList(headList);
        // 封装子节点
        int depth = 1;
        headList.forEach(x -> x.handleSunNodeList(groupList, allGroupList, depth));

        // 封装属性
        List<Long> groupIdList = allGroupList.stream().map(ProductTemplateNodeDTO::getGroupId).collect(Collectors.toList());
        List<ProductTemplateNodeAttributeDTO> itemList = itemMapper.getInfoByGroupId(groupIdList);
        if (CollectionUtils.isEmpty(itemList)) {
            return res;
        }
        List<Long> attributeIdList = itemList.stream()
                .map(ProductTemplateNodeAttributeDTO::getAttributeId).collect(Collectors.toList());
        List<Long> itemIdList = itemList.stream()
                .map(ProductTemplateNodeAttributeDTO::getId).collect(Collectors.toList());
        Map<Long, ProductTemplateNodeAttributeDTO> itemIdMap = itemList.stream()
                .collect(Collectors.toMap(ProductTemplateNodeAttributeDTO::getId, v -> v, (k1, k2) -> k1));
        Map<Long, ProductTemplateNodeAttributeDTO> itemAttributeIdMap = itemList.stream()
                .collect(Collectors.toMap(ProductTemplateNodeAttributeDTO::getAttributeId, v -> v, (k1, k2) -> k1));
        List<BaseProductTemplateRuleDO> ruleList = new LambdaQueryChainWrapper<>(ruleMapper)
                .in(BaseProductTemplateRuleDO::getGitemId,itemIdList)
                .in(BaseProductTemplateRuleDO::getBindGitemId,itemIdList)
                .in(BaseProductTemplateRuleDO::getIsDelete,CommonConstants.IS_DELETE_N)
                .list();

        // 子设置父类绑定条件
        Map<Long, BaseProductTemplateRuleDO> ruleBindMap = ruleList.stream()
                .collect(Collectors.toMap(BaseProductTemplateRuleDO::getBindAttributeId, v -> v, (k1, k2) -> k1));
        Set<Long> triggerIds = new HashSet<>();

        itemList.forEach(i->{
            BaseProductTemplateRuleDO r = ruleBindMap.get(i.getAttributeId());
            if(Objects.nonNull(r)){
                i.setTriggerAttributeCode(r.getAttributeCode());
                ProductTemplateNodeAttributeDTO item = itemAttributeIdMap.get(r.getAttributeId());
                if(Objects.nonNull(item)){
                    i.setTriggerValueCode(item.getValueCode());
                    i.setTriggerIsMultipleChoice(item.getIsMultipleChoice());
                }
                i.setTriggerValue(r.getTriggerValue());
                triggerIds.add(r.getAttributeId());
            }
        });

        // 设置属性触发值id转为文本信息
        if (!triggerIds.isEmpty()) {
            List<BaseAttributeValueDO> triggerAttributeValueList = new LambdaQueryChainWrapper<>(attributeValueMapper)
                    .eq(BaseAttributeValueDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .eq(BaseAttributeValueDO::getStatus, CommonConstants.ENABLE)
                    .in(BaseAttributeValueDO::getAttributeId, triggerIds)
                    .list();
            Map<Long, String> triggerAttributeValueMap = triggerAttributeValueList
                    .stream().collect(Collectors.toMap(BaseAttributeValueDO::getId, BaseAttributeValueDO::getValue, (k1,k2) ->k1));
            Map<Long, BaseAttributeValueDO> attributeValueMap = triggerAttributeValueList
                    .stream().collect(Collectors.toMap(BaseAttributeValueDO::getId, i -> i, (k1,k2) ->k1));
            itemList.forEach(i->{
                if (AttributeValueCodeEnum.LEVEL_SELECT.getCode().equals(i.getTriggerValueCode())) {
                    if (StringUtils.isNotBlank(i.getTriggerValue())) {
                        List<String> valueList = new ArrayList<>();
                        for (String s : i.getTriggerValue().split(",")) {
                            BaseAttributeValueDO attributeValueDO = attributeValueMap.get(Long.valueOf(s));
                            String idPath = attributeValueDO.getIdPath();
                            List<String> pathList = new ArrayList<>();
                            for (String valueId : idPath.split("/")) {
                                pathList.add(triggerAttributeValueMap.get(Long.valueOf(valueId)));
                            }
                            valueList.add(String.join("/", pathList));
                        }
                        i.setTriggerValueTxt(String.join(",", valueList));
                    }
                } else {
                    if (StringUtils.isNotBlank(i.getTriggerValue())) {
                        List<String> valueList = new ArrayList<>();
                        for (String s : i.getTriggerValue().split(",")) {
                            valueList.add(triggerAttributeValueMap.get(Long.valueOf(s)));
                        }
                        i.setTriggerValueTxt(String.join(",", valueList));
                    }
                }
            });
        }

        if(style){
            Map<Long, List<ProductTemplateNodeAttributeDTO>> itemMap = itemList.stream()
                    .collect(Collectors.groupingBy(ProductTemplateNodeAttributeDTO::getGroupId));
            allGroupList.forEach(x -> {
                List<ProductTemplateNodeAttributeDTO> gitemList = itemMap.get(x.getId());
                if (!CollectionUtils.isEmpty(gitemList)) {
                    x.setAttributeList(gitemList);
                }
            });
        } else {
            // 父设置子list
            Map<Long, List<BaseProductTemplateRuleDO>> ruleGroup = ruleList.stream()
                    .collect(Collectors.groupingBy(BaseProductTemplateRuleDO::getAttributeId));
            itemList.forEach(i->{
                List<BaseProductTemplateRuleDO> rules = ruleGroup.get(i.getAttributeId());
                if(CollectionUtils.isEmpty(rules)){
                    return;
                }
                List<ProductTemplateNodeAttributeDTO> sunItemList = rules.stream()
                        .map(x -> itemIdMap.get(x.getBindGitemId()))
                        .filter(Objects::nonNull).collect(Collectors.toList());
                i.setTriggerList(sunItemList);
            });
            Map<Long, List<ProductTemplateNodeAttributeDTO>> itemMap = itemList.stream()
                    .filter(x->Objects.isNull(x.getTriggerValue()))
                    .collect(Collectors.groupingBy(ProductTemplateNodeAttributeDTO::getGroupId));
            allGroupList.forEach(x -> {
                List<ProductTemplateNodeAttributeDTO> gitemList = itemMap.get(x.getId());
                if (!CollectionUtils.isEmpty(gitemList)) {
                    x.setAttributeList(gitemList);
                }
            });
        }

        // 封装下拉列AttributeReqDTO result=new AttributeReqDTO();
        List<ValueListByAttributeIdDTO> valueList = attributeValueMapper.getValuesByAttributeIdList(attributeIdList);
        if (!CollectionUtils.isEmpty(valueList)) {
            Map<Long, List<ValueListByAttributeIdDTO>> valueMap = valueList.stream()
                    .collect(Collectors.groupingBy(ValueListByAttributeIdDTO::getAttributeId));
            itemList.forEach(x -> {
                x.setValueList(valueMap.getOrDefault(x.getAttributeId(), new ArrayList<>()));
                x.setValueList(x.getValueList().stream()
                        .filter(tree -> Objects.isNull(tree.getParentId()))
                        .peek((dept) -> dept.setChildrenList(getChildrenNode(dept, x.getValueList())))
                        .collect(Collectors.toList()));
            });
        }

        return res;
    }

    /**
     * 获取子节点
     *
     * @param parent  parent
     * @param dtoList dto列表
     * @author jp
     * @date 2023/12/26
     */
    private List<ValueListByAttributeIdDTO> getChildrenNode(ValueListByAttributeIdDTO parent, List<ValueListByAttributeIdDTO> dtoList) {
        return dtoList.stream().filter((tree) -> Objects.nonNull(tree.getParentId()) && tree.getParentId().equals(parent.getId()))
                .peek((tree) -> tree.setChildrenList(getChildrenNode(tree, dtoList))).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long addTemplate(AddOrUpdateTemplateReqDTO in) {

        BaseProductTemplateDO templateDO = new BaseProductTemplateDO();
        BeanUtils.copyProperties(in,templateDO);
        templateDO.setId(IdGenUtil.getId());
        templateDO.setTemplateCode("T"+ DateUtil.format(new Date(), "yyyy-MM-dd_HH_mm_ss"));
        templateDO.setTemplateName(in.getTemplateName());
        templateDO.setDescription(in.getDescription());
        templateDO.setCreateTime(LocalDateTime.now());
        templateDO.setUpdateTime(LocalDateTime.now());
        templateDO.setCreateUserId(UserUtil.getUserId());
        templateDO.setUpdateUserId(UserUtil.getUserId());
        this.save(templateDO);

        templateGroupService.addTemplate(templateDO.getId(),in.getNodeList());

        return templateDO.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long updateTemplate(AddOrUpdateTemplateReqDTO in) {

        new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .eq(BaseProductTemplateDO::getId,in.getProductTemplateId())
                .set(BaseProductTemplateDO::getTemplateName,in.getTemplateName())
                .set(BaseProductTemplateDO::getDescription,in.getDescription())
                .set(BaseProductTemplateDO::getStyleName,in.getStyleName())
                .set(BaseProductTemplateDO::getStyleStatus,in.getStyleStatus())
                .set(BaseProductTemplateDO::getSkuStatus,in.getSkuStatus())
                .set(BaseProductTemplateDO::getSupplierId,in.getSupplierId())
                .set(BaseProductTemplateDO::getUpdateTime,LocalDateTime.now())
                .set(BaseProductTemplateDO::getUpdateUserId,UserUtil.getUserId())
                .update();

        // 删除相关数据
        new LambdaUpdateChainWrapper<>(templateGroupService.getBaseMapper())
                .eq(BaseProductTemplateGroupDO::getTemplateId,in.getProductTemplateId())
                .remove();
        new LambdaUpdateChainWrapper<>(templateGitemService.getBaseMapper())
                .eq(BaseProductTemplateGitemDO::getTemplateId,in.getProductTemplateId())
                .remove();
        new LambdaUpdateChainWrapper<>(templateRuleService.getBaseMapper())
                .eq(BaseProductTemplateRuleDO::getTemplateId,in.getProductTemplateId())
                .remove();

        templateGroupService.addTemplate(in.getProductTemplateId(),in.getNodeList());

        return in.getProductTemplateId();
    }

    @Override
    public List<BaseProductTemplateDO> getTemplateList() {

        return new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(BaseProductTemplateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .orderByAsc(BaseProductTemplateDO::getCreateTime)
                .list();
    }

    @Override
    public void delTemplate(Long id) {
        BaseProductTemplateDO productTemplate = this.getById(id);
        if (Objects.nonNull(productTemplate) && !productTemplate.getStatus().equals(CommonConstants.DISABLE)) {
            throw new KingHoodException(-1 , "只有停用状态的才可操作删除");
        }

        long count = new LambdaQueryChainWrapper<>(productBaseMapper)
                .eq(ProductBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(ProductBaseDO::getProductTemplateId, id)
                .count();
        if (count > 0) {
            throw new KingHoodException(-1, "存在关联商品，请移除后再删");
        }
        LocalDateTime now = LocalDateTime.now();
        this.lambdaUpdate().set(BaseProductTemplateDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(BaseProductTemplateDO::getUpdateTime, now)
                .set(BaseProductTemplateDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseProductTemplateDO::getId, id)
                .eq(BaseProductTemplateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();

        templateGitemService.lambdaUpdate().set(BaseProductTemplateGitemDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(BaseProductTemplateGitemDO::getUpdateTime, now)
                .set(BaseProductTemplateGitemDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseProductTemplateGitemDO::getTemplateId, id)
                .eq(BaseProductTemplateGitemDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();

        templateGroupService.lambdaUpdate().set(BaseProductTemplateGroupDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(BaseProductTemplateGroupDO::getUpdateTime, now)
                .set(BaseProductTemplateGroupDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseProductTemplateGroupDO::getTemplateId, id)
                .eq(BaseProductTemplateGroupDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();

        templateRuleService.lambdaUpdate().set(BaseProductTemplateRuleDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(BaseProductTemplateRuleDO::getUpdateTime, now)
                .set(BaseProductTemplateRuleDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseProductTemplateRuleDO::getTemplateId, id)
                .eq(BaseProductTemplateRuleDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();
    }

    @Override
    public void updateTemplateStatus(StatusReqDTO param) {
        this.lambdaUpdate().set(BaseProductTemplateDO::getStatus, param.getStatus())
                .set(BaseProductTemplateDO::getUpdateTime, LocalDateTime.now())
                .set(BaseProductTemplateDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseProductTemplateDO::getId, param.getId())
                .eq(BaseProductTemplateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();
    }

    @Override
    public Object pageTemplate(ListTemplateQueryDTO param) {
        Page<TemplateListVO> result = this.baseMapper.pageTemplate(KingHoodPageUtil.getPage(param, param), param);

        Set<Long> userIdList = new HashSet<>();
        for (TemplateListVO record : result.getRecords()) {
            userIdList.add(record.getCreateUserId());
            userIdList.add(record.getUpdateUserId());
            record.setStatusTxt(StatusEnum.getNameByStatus(record.getStatus()));
        }
        userIdList.remove(null);
        if (!CollectionUtils.isEmpty(userIdList)) {
            Map<Long, UserRemoteVo> userMap = userRemote.getUserByIds(new ArrayList<Long>(userIdList));
            for (TemplateListVO record : result.getRecords()) {
                record.setCreateUserName(UserNameUtil.getName(record.getCreateUserId(), userMap));
                record.setUpdateUserName(UserNameUtil.getName(record.getUpdateUserId(), userMap));
            }
        }
        return KingPageResult.getResult(result);
    }
}
